﻿using System.Linq.Expressions;
using System.Reflection;
using DatabaseProxy.Attributes;

namespace DatabaseProxy
{
    public class SqlPageVisitor<T> : ExpressionVisitor where T : IDatabaseTable
    {
        public Queue<string> sql_stack;
        public SqlPageVisitor()
        {
            sql_stack = new Queue<string>();
        }
        public string GetSql()
        {
            string sql = string.Join(' ', sql_stack);
            sql_stack.Clear();
            return sql;
        }

        public void OrderAndPage(PropertyInfo? propertyInfo, string direction = "ASC", int page = 0, int pageSize = 0)
        {
            bool haspage = true;
            sql_stack.Enqueue($" ORDER BY ");
            if (propertyInfo != null)
            {
                string columnName = propertyInfo.Name;
                if (propertyInfo.IsDefined(typeof(ColumnNameAttribute), false))
                {
                    ColumnNameAttribute? columnNameAttribute = propertyInfo.GetCustomAttribute<ColumnNameAttribute>();
                    columnName = columnNameAttribute?.Name ?? columnName;
                }
                sql_stack.Enqueue(columnName);
                if (direction == "ASC" || direction == "DESC")
                {
                    sql_stack.Enqueue(direction);
                }
            }
            else
            {
                var type = typeof(T);
                var primaryProperty = type.GetProperties().Where(l => l.IsDefined(typeof(PrimaryKeyAttribute))).FirstOrDefault();
                if (primaryProperty == null)
                {
                    sql_stack.Dequeue();
                    haspage = false;
                }
                else
                {
                    if (primaryProperty.IsDefined(typeof(ColumnNameAttribute), false))
                    {
                        ColumnNameAttribute? columnNameAttribute = primaryProperty.GetCustomAttribute<ColumnNameAttribute>();
                        string columnName = columnNameAttribute?.Name ?? primaryProperty.Name;
                        sql_stack.Enqueue(columnName);
                    }
                    if (direction != "ASC" && direction != "DESC")
                    {
                        sql_stack.Enqueue(direction);
                    }
                }
            }

            if (haspage && page != 0 && pageSize != 0)
            {
                sql_stack.Enqueue($" OFFSET {pageSize * (page - 1)} ROWS FETCH NEXT {pageSize} ROWS ONLY ");
            }
        }
    }
}